import { BaseService } from '@/core/base.service';
import { BankListDto, BankQueryDto, BankTypeListDto } from '@/dtos';
import { halt } from '@/utils';
import { Injectable } from '@nestjs/common';
import { Bank, Prisma } from '@prisma/client';

@Injectable()
export class BankService extends BaseService {
  async query({ type, params, sort }: BankQueryDto) {
    const { current = 1, pageSize = 20, keyword, ...where } = params;

    let sql = `
      SELECT #{fields} FROM UnionBank AS t
      WHERE t.bank = '${type}'
      ${!!keyword ? `AND t.name LIKE '%${keyword}%'` : ''}
    `;

    const [{ count }] = await this.prisma.$queryRawUnsafe<[{ count: number }]>(
      sql.replace('#{fields}', 'COUNT(t.id) AS count'),
    );

    const list = await this.prisma.$queryRawUnsafe<Bank[]>(
      `${sql.replace('#{fields}', 't.id, t.name, t.code')}
      LIMIT ${pageSize} 
      OFFSET ${(current - 1) * pageSize}
      `,
    );

    const total = count ? Number(count) : 0;
    const totalPage = Math.ceil(total / pageSize);
    const hasMore = current < totalPage;

    return {
      total,
      totalPage,
      hasMore,
      current,
      pageSize,
      list,
    };
  }

  async getTypeList({ params }: BankTypeListDto) {
    const { current = 1, pageSize = 20, keyword, ...where } = params;

    let sql = `
      SELECT #{fields} FROM UnionBank AS t
      WHERE 1 = 1
      ${
        !!keyword
          ? keyword
              .split(' ')
              .map((k) => `AND (t.bank LIKE '%${k}%' OR t.name LIKE '%${k}%')`)
              .join(' ')
          : ''
      }
      GROUP BY t.bank, t.id
    `;

    const res = await this.prisma.$queryRawUnsafe<[{ count: number }]>(
      sql.replace('#{fields}', 'COUNT(DISTINCT t.bank) AS count'),
    );

    const list = await this.prisma.$queryRawUnsafe<Bank[]>(
      `${sql.replace('#{fields}', 't.id, t.name, t.bank, t.code')}
      ORDER BY t.id ASC
      LIMIT ${pageSize} 
      OFFSET ${(current - 1) * pageSize} 
      `,
    );

    const total = res?.length ?? 0;
    const totalPage = Math.ceil(total / pageSize);
    const hasMore = current < totalPage;

    return {
      total,
      totalPage,
      hasMore,
      current,
      pageSize,
      list,
    };
  }

  async getList(ownerId, { params, sort }: BankListDto) {
    const { current = 1, pageSize = 20, keyword, ...where } = params;

    let sql = `
      SELECT #{fields} FROM Bank AS t
      WHERE t.isDeleted = false
        AND t.ownerId = ${ownerId}
    `;

    const [{ count }] = await this.prisma.$queryRawUnsafe<[{ count: number }]>(
      sql.replace('#{fields}', 'COUNT(t.id) AS count'),
    );

    const list = await this.prisma.$queryRawUnsafe<Bank[]>(
      `${sql.replace('#{fields}', 't.id, t.bank, t.bankNo, t.bankCode')}
      ORDER BY ${
        !!sort && Object.keys(sort).length > 0
          ? Object.entries(sort)
              .map(([k, v]) => `t.${k} ${v === 'descend' ? 'DESC' : 'ASC'}`)
              .join(',')
          : 't.createdAt DESC'
      }
      LIMIT ${pageSize} 
      OFFSET ${(current - 1) * pageSize}
      `,
    );

    const total = count ? Number(count) : 0;
    const totalPage = Math.ceil(total / pageSize);
    const hasMore = current < totalPage;

    return {
      total,
      totalPage,
      hasMore,
      current,
      pageSize,
      list,
    };
  }

  async create(
    ownerId: number,
    data: Prisma.BankCreateWithoutOwnerInput,
  ): Promise<Bank> {
    const bank = await this.prisma.bank.findFirst({
      where: {
        bankNo: data.bankNo,
        ownerId,
        isDeleted: false,
      },
    });
    if (!!bank) {
      return halt('该卡号已绑定');
    }
    return await this.prisma.bank.create({
      data: {
        ...data,
        ownerId,
      },
    });
  }

  async remove(where: Prisma.BankWhereUniqueInput): Promise<Bank> {
    return this.prisma.bank.update({
      where,
      data: {
        isDeleted: true,
      },
    });
  }
}
